﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using FRW.Common.Extensions;

namespace Money.Plugins.Import.TescoImportV2
{
    public partial class TransactionMatchForm : Form
    {
        private enum State
        {
            Add,
            Edit,
            View,
            Saved,
            Cancel
        }

        bool _formLoaded = false;

        State _state = State.View;

        List<TransactionMatch> _matchRules = new List<TransactionMatch>();
        private Categories _categories;
        private TransactionMatch _editingMatch = null;
        private int _lastSelectedRow = -1;
        private bool _enableClicked = false;

        public TransactionMatchForm(List<TransactionMatch> categoryMatches, Categories categories)
        {
            InitializeComponent();

            _categories = categories;
            _matchRules = categoryMatches;

            _grid.AutoGenerateColumns = false;

            SetGridDataSource();

            clmCategory.DataSource = _categories;
            clmCategory.DisplayMember = "Name";
            clmCategory.ValueMember = "Id";

            _originalCategoryId.DataSource = _categories;
            _originalCategoryId.DisplayMember = "Name";
            _originalCategoryId.ValueMember = "Id";

            _originalCategory.DataSource = _categories;
            _originalCategory.DisplayMember = "Name";
            _originalCategory.ValueMember = "Id";

            // old and new categories appear to be linked for some reason?
            _newCategory.DataSource = _categories;
            _newCategory.DisplayMember = "Name";
            _newCategory.ValueMember = "Id";

            _actionButton.Enabled = false;

            foreach (string type in Enum.GetNames(typeof(Transaction.TransactionType)))
            {
                _type.Items.Add(type);
            }
        }

        private void PopulateEditingControls(TransactionMatch match)
        {
            if (match.RegularExpression == null || String.IsNullOrWhiteSpace(match.RegularExpression))
            {
                _description.Text = String.Empty;
                _enableDescription.Checked = false;
            }
            else
            {
                _description.Text = match.RegularExpression;
                _enableDescription.Checked = true;
            }

            if (match.OriginalCategoryId == null)
            {
                _originalCategory.SelectedIndex = -1;
                _originalCategory.SelectedItem = null;
                _enableCategory.Checked = false;
            }
            else
            {
                _originalCategory.SelectedValue = match.OriginalCategoryId;
                _enableCategory.Checked = true;
            }

            if (match.NewCategoryId == null)
            {
                _newCategory.SelectedIndex = -1;
                _newCategory.SelectedItem = null;
                _enableNewCategory.Checked = false;
            }
            else
            {
                _newCategory.SelectedValue = match.NewCategoryId;
                _enableNewCategory.Checked = true;
            }

            if (match.Type == null)
            {
                _type.SelectedIndex = -1;
                _enableType.Checked = false;
            }
            else
            {
                _type.Text = match.Type.ToString();
                _enableType.Checked = true;
            }

            if (match.MinAmount == null && match.MaxAmount == null)
            {
                _maxAmount.Text = String.Empty;
                _minAmount.Text = String.Empty;
                _enableAmount.Checked = false;
            }
            else
            {
                _minAmount.Text = match.MinAmount.ToString();
                _maxAmount.Text = match.MaxAmount.ToString();
                _enableAmount.Checked = true;
            }

            _priority.Text = match.Priority.ToString();
            _terminate.Checked = match.Terminate;

            _enableClicked = false;
        }

        private void SetGridDataSource()
        {
            var dataSource = from descriptionMatch in _matchRules orderby descriptionMatch.Priority descending select descriptionMatch;

            _grid.DataSource = null;
            _grid.DataSource = dataSource.ToList();
        }

        private void _actionButton_Click(object sender, EventArgs e)
        {
            TransactionMatch transactionMatch = null;

            switch (_state)
            {
                case State.Edit:
                    transactionMatch = _editingMatch;
                    break;

                case State.Add:
                    transactionMatch = new TransactionMatch();
                    _matchRules.Add(transactionMatch);
                    break;
            }

            PopulateTransactionMatch(transactionMatch);

            ClearControls();

            SetGridDataSource();

            SelectRow(transactionMatch);

            _state = State.View;
        }

        private void PopulateTransactionMatch(TransactionMatch transactionMatch)
        {
            try
            {
                transactionMatch.Priority = Convert.ToInt32(_priority.Text);
            }
            catch
            {
                transactionMatch.Priority = 100;
            }

            if (_enableType.Checked)
            {
                Transaction.TransactionType? type = null;

                if (!String.IsNullOrWhiteSpace(_type.Text))
                {
                    try
                    {
                        type = (Transaction.TransactionType)Enum.Parse(typeof(Transaction.TransactionType), _type.Text);
                    }
                    catch
                    {
                    }
                }

                transactionMatch.Type = type;
            }
            else
            {
                transactionMatch.Type = null;
            }

            transactionMatch.Terminate = _terminate.Checked;

            if (_enableDescription.Checked)
            {
                transactionMatch.RegularExpression = _description.Text;
            }
            else
            {
                transactionMatch.RegularExpression = null;
            }

            if (_enableCategory.Checked)
            {
                transactionMatch.OriginalCategoryId = (int)_originalCategory.SelectedValue;
            }
            else
            {
                transactionMatch.OriginalCategoryId = null;
            }

            if (_enableNewCategory.Checked)
            {
                transactionMatch.NewCategoryId = (int)_newCategory.SelectedValue;
            }
            else
            {
                transactionMatch.NewCategoryId = null;
            }

            if (_enableAmount.Checked)
            {
                try
                {
                    transactionMatch.MaxAmount = Convert.ToDecimal(_maxAmount.Text);
                }
                catch
                {
                    transactionMatch.MaxAmount = null;
                }

                try
                {
                    transactionMatch.MinAmount = Convert.ToDecimal(_minAmount.Text);
                }
                catch
                {
                    transactionMatch.MinAmount = null;
                }
            }
            else
            {
                transactionMatch.MaxAmount = null;
                transactionMatch.MinAmount = null;
            }
        }

        private void _clearButton_Click(object sender, EventArgs e)
        {
            ClearControls();
            EnableControls(true);
            _state = State.Add;
            _grid.ClearSelection();
        }

        private void ClearControls()
        {
            _description.Text = String.Empty;
            _enableDescription.Checked = false;
            _enableNewCategory.Checked = false;
            _enableType.Checked = false;
            _enableCategory.Checked = false;
            _priority.Text = String.Empty;
            _originalCategory.Text = String.Empty;
            _newCategory.Text = String.Empty;
            _type.Text = String.Empty;

            _terminate.Checked = false;

            _originalCategory.SelectedItem = null;
            _originalCategory.SelectedIndex = -1;
            _newCategory.SelectedItem = null;
            _newCategory.SelectedIndex = -1;
            _type.SelectedItem = null;

            _editingMatch = null;
            _lastSelectedRow = -1;

            _maxAmount.Text = String.Empty;
            _minAmount.Text = String.Empty;
        }

        private void _descriptionGrid_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {

        }

        private void _descriptionGrid_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            DataGridView grid = sender as DataGridView;

            if (grid == null)
            {
                return;
            }

            if (e.RowIndex < 0)
            {
                return;
            }

            switch (e.Button)
            {
                case System.Windows.Forms.MouseButtons.Left:
                    break;

                case System.Windows.Forms.MouseButtons.Right:
                    if (grid.SelectedRows.Count > 1)
                    {
                        deleteEntriesMenuItem.Text = "Delete Entries";
                    }
                    else
                    {
                        deleteEntriesMenuItem.Text = "Delete Entry";
                    }
                    contextMenu.Show(System.Windows.Forms.Cursor.Position);
                    break;
            }
        }

        private void deleteEntriesMenuItem_Click(object sender, EventArgs e)
        {
            DataGridView grid = _grid;

            if (grid != null)
            {
                if (grid.SelectedRows.Count > 0)
                {
                    DialogResult result = MessageBox.Show("Do you want to delete " + grid.SelectedRows.Count + " entries?", "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);

                    if (result == System.Windows.Forms.DialogResult.Yes)
                    {
                        foreach (DataGridViewRow row in grid.SelectedRows)
                        {
                            TransactionMatch match = row.DataBoundItem as TransactionMatch;

                            if (match != null)
                            {
                                _matchRules.Remove(match);
                            }
                        }

                        SetGridDataSource();
                        _clearButton_Click(this, new EventArgs());
                    }
                }
            }
        }

        private void SelectRow(TransactionMatch match)
        {
            int firstRow = _grid.FirstDisplayedScrollingRowIndex;
            int rows = _grid.RowCount;

            int rowNumber = 0;

            _grid.ClearSelection();

            foreach (DataGridViewRow row in _grid.Rows)
            {
                TransactionMatch rowMatch = row.DataBoundItem as TransactionMatch;

                if (rowMatch == match)
                {
                    rowNumber = row.Index;
                    row.Selected = true;
                }
            }

            if (rowNumber > firstRow && rowNumber < (rows + firstRow))
            {
            }
            else
            {
                _grid.FirstDisplayedScrollingRowIndex = rowNumber;
            }
        }

        private void addNewEntryMenuItem_Click(object sender, EventArgs e)
        {
            _grid.ClearSelection();
        }

        private void _descriptionGrid_SelectionChanged(object sender, EventArgs e)
        {
            // dont do anything if we are not fully loaded yet
            if (!_formLoaded)
            {
                return;
            }

            // if last row is equal to -2 then this is a special case where we do not want to do anything as we are mid-operation
            if (_lastSelectedRow == -2)
            {
                return;
            }

            // if we have no selection then we can add a record
            if (_grid.SelectedRows.Count == 0)
            {
                EnableControls(true);
                ClearControls();
                _state = State.Add;
                _lastSelectedRow = -1;
            }
            // if we have one selection then we can change an entry
            else if (_grid.SelectedRows.Count == 1)
            {
                if (_lastSelectedRow == _grid.SelectedRows[0].Index)
                {
                    return;
                }

                TransactionMatch categoryMatch = _grid.SelectedRows[0].DataBoundItem as TransactionMatch;

                if (categoryMatch != null)
                {
                    // TODO we need to prevent changing selected item if we have made edits
                    // HACK at least give some warning that we may lose edits
                    if (_editingMatch != null && _editingMatch != categoryMatch && EditChanged(_editingMatch))
                    {
                        if (MessageBox.Show("The current edit has not been completed, do you want to cancel this edit?", "Cancel Current Edit!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.No)
                        {
                            int restoreRow = _lastSelectedRow;
                            _lastSelectedRow = -2;
                            _grid.SelectedRows[0].Selected = false;
                            _grid.Rows[restoreRow].Selected = true;
                            _lastSelectedRow = restoreRow;
                            return;
                        }
                    }
                    PopulateEditingControls(categoryMatch);

                    EnableControls(true);
                    _state = State.Edit;
                    _editingMatch = categoryMatch;
                    _lastSelectedRow = _grid.SelectedRows[0].Index;
                }
                else
                {
                    _lastSelectedRow = -1;
                    EnableControls(true);
                    ClearControls();
                    _state = State.Add;
                }
            }
            // if we have more than one then we cannot od anything other than delete so disable edit controls
            else
            {
                EnableControls(false);

                ClearControls();
                _state = State.View;
            }

            ConfigureActionButton();
        }

        /// <summary>
        /// This method is called when any data entry object is edited on the screen. Check if we should change control operation if we have a changed value
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ValidAfterEdit(object sender, EventArgs e)
        {
            ConfigureActionButton();
        }

        private void ConfigureActionButton()
        {
            switch(_state)
            {
                case State.Add:
                    _actionButton.Text = _state.ToString();
                    if (((_enableDescription.Checked && !string.IsNullOrWhiteSpace(_description.Text)) ||
                        (_enableCategory.Checked && _originalCategory.SelectedIndex != -1) || 
                        (_enableAmount.Checked) && (!String.IsNullOrWhiteSpace(_minAmount.Text) || !String.IsNullOrWhiteSpace(_maxAmount.Text))) && 
                       ((_enableNewCategory.Checked && _newCategory.SelectedIndex != -1) || 
                        (_enableType.Checked && _type.SelectedIndex != -1)))
                    {
                        _actionButton.Enabled = true;
                    }
                    else
                    {
                        _actionButton.Enabled = false;
                    }
                    break;

                case State.Edit:
                    _actionButton.Text = _state.ToString();

                    if (EditChanged(_editingMatch) &&
                        ((_enableDescription.Checked && !string.IsNullOrWhiteSpace(_description.Text)) ||
                         (_enableCategory.Checked && _originalCategory.SelectedIndex != -1) ||
                         (_enableAmount.Checked) && (!String.IsNullOrWhiteSpace(_minAmount.Text) || !String.IsNullOrWhiteSpace(_maxAmount.Text))) &&
                       ((_enableNewCategory.Checked && _newCategory.SelectedIndex != -1) ||
                        (_enableType.Checked && _type.SelectedIndex != -1)))
                    {
                        _actionButton.Enabled = true;
                    }
                    else
                    {
                        _actionButton.Enabled = false;
                    }
                    break;

                default:
                    _actionButton.Enabled = false;
                    break;
            }
        }

        private bool EditChanged(TransactionMatch match)
        {
            bool changed = false;

            // TODO this needs expanded so that any change is detected
            if (!_description.Text.Equals(match.RegularExpression) || _enableClicked)
            {
                changed = true;
            }

            return changed;
        }

        private void EnableControls(bool state)
        {
            _priority.Enabled = state;
            _terminate.Enabled = state;
        }

        private void _enable_Click(object sender, EventArgs e)
        {
            _enableClicked = true;
            ValidAfterEdit(sender, e);
        }

        private void _enableDescription_CheckedChanged(object sender, EventArgs e)
        {
            _description.Enabled = _enableDescription.Checked;
        }

        private void _enableCategory_CheckedChanged(object sender, EventArgs e)
        {
            _originalCategory.Enabled = _enableCategory.Checked;
        }

        private void _enableAmount_CheckedChanged(object sender, EventArgs e)
        {
            _maxAmount.Enabled = _minAmount.Enabled = _enableAmount.Checked;
        }

        private void _enableNewCategory_CheckedChanged(object sender, EventArgs e)
        {
            _newCategory.Enabled = _enableNewCategory.Checked;
        }

        private void _enableType_CheckStateChanged(object sender, EventArgs e)
        {
            _type.Enabled = _enableType.Checked;
        }

        private void TransactionMatchForm_Load(object sender, EventArgs e)
        {
            _formLoaded = true;

            _clearButton_Click(this, new EventArgs());
        }
    }
}
